-- $LastChangedDate: 2007-06-01 02:52:33 +0200 (Fri, 01 Jun 2007) $
-- $LastChangedRevision: 149 $
-- $LastChangedBy: vicente $

-- packages de ada
WITH Ada.Task_Identification;
USE Ada.Task_Identification;
WITH Ada.Text_Io;
USE Ada.Text_Io;
WITH Ada.Numerics.Discrete_Random;

-- packages del gimnasio
WITH Listas.Tabla_Ejercicios_Lists;
WITH Tiposprotegidos.Log;

PACKAGE BODY Tareas.Cliente IS

   -- variables para la funcion crear_cliente
   PACKAGE Cliente_Al_Azar IS NEW Ada.Numerics.Discrete_Random
      (Tipoedad);
   G : Cliente_Al_Azar.Generator;

   TASK BODY Cliente IS
      Entrevistado : Boolean       := False;
      Ej           : Ejerciciotype;
      -- tiempo durante el que hara el ejercicio
      Tiempo : Duration;
      Aptr   : Aparatoptr;
      Tabla  : Listas.Tabla_Ejercicios_Lists.List_Type;
      -- variable para controlar si tras una emergencia un medico
      -- nos aconseja irnos a casa
      Vete_A_Casa : Boolean := False;
   BEGIN
      Print("cliente: start");
      -- actualizar log
      Tiposprotegidos.Log.Log_Add(Tiposprotegidos.Log.Cliente_Cantidad);

      -- el cliente necesita ser entrevistado al inicio
      WHILE NOT Entrevistado AND NOT Term_Signal LOOP
         Catch_Monitor_Emergency_Entrevista : DECLARE
         BEGIN
            Print("cliente: solicitando monitor para entrevista");
            -- inicialmente el cliente trata de solicitar una entrevista con el monitor
            Gm.Monitorpetitionentrevista(Datos, Tabla);

            Entrevistado := True;

            -- actualizar log
            Tiposprotegidos.Log.Log_Add(Tiposprotegidos.Log.Cliente_Entrevistado);

            -- Solo se ejecuta si el monitor no ha sido
            -- llamado para atender a un cliente enfermo
            DELAY T_Retry_Entrevista;
         EXCEPTION
            WHEN Tasking_Error =>
               -- El monitor ha sido llamado para atender a un cliente enfermo
               Print("cliente: entrevista cancelada");
         END Catch_Monitor_Emergency_Entrevista;
      END LOOP;

      Print("cliente: entrevista finalizada");

      -- el cliente va a empezar a entrenar
      LOOP
         Catch_Monitor_Emergency_Ejercicio : DECLARE
         BEGIN
            Print(
               "cliente: solicitando monitor para pedir el siguiente ejercicio");

            Gm.Monitorpetitionejercicio(Tabla, Ej, Tiempo);

            -- solo se ejecutara si no salta la excepcion y ademas se recomendo algun ejercicio
            IF Ej /= Sinejercicio THEN
               -- actualizar log
               Tiposprotegidos.Log.Log_Add(Tiposprotegidos.Log.Ejercicios_Asignados);

               Print("cliente: solicitando aparato para hacer el ejercicio " &
                  Ej);

               Ga.Get_Aparato(Aptr, Ej);
               Print("cliente: me han asignado el aparato " & Image(Aptr'
                     Identity));

               Print("cliente: iniciando entrenamiento en el aparato " &
                  Image(Aptr'Identity));
               -- el tiempo del entrenamiento fue determinado al pedir ejercicio
               Aptr.Entrenar(Ej, Tiempo, Datos, Vete_A_Casa);
               Print("cliente: finalizado entrenamiento en el aparato " &
                  Image(Aptr'Identity));
            END IF;
         EXCEPTION
            WHEN Tasking_Error =>
               -- El monitor ha sido llamado para atender a un cliente enfermo
               Print("cliente: peticion de ejercicio cancelada");
         END Catch_Monitor_Emergency_Ejercicio;

         EXIT WHEN Ej = Sinejercicio OR Vete_A_Casa OR Term_Signal;

      END LOOP;

      -- si el cliente ha finalizado el entrenamiento de forma normal
      IF Ej=Sinejercicio THEN
         -- actualizar log
         Tiposprotegidos.Log.Log_Add(Tiposprotegidos.Log.Cliente_Entreno_Completo);
         Print("cliente: He terminado de entrenar, me voy a casa");
      ELSE
         IF Vete_A_Casa THEN
            -- actualizar log
            Tiposprotegidos.Log.Log_Add(Tiposprotegidos.Log.Cliente_Vete_A_Casa);
            Print("cliente: Tras sufrir una emergencia el medico me ha recomendado irme a casa");
         ELSE
            -- actualizar log
            Tiposprotegidos.Log.Log_Add(Tiposprotegidos.Log.Cliente_Entreno_Completo);
            Print_Term("cliente: Me voy porque el gimnasio va a cerrar");
         END IF;
      END IF;
   EXCEPTION
      WHEN Ocurrencia : OTHERS =>
         Put_Line ("Cliente: "&Ada.Exceptions.Exception_Information (Ocurrencia));
   END Cliente;

   FUNCTION Crear_Cliente RETURN Datosclienteptr IS
      Datos : DatosclientePtr;
   BEGIN
      Cliente_Al_Azar.Reset(G);
      Datos:= NEW Datoscliente;
      Datos.Edad := Cliente_Al_Azar.Random (G);
      Datos.Condicionfisica := Tareas.Regular;
      RETURN Datos;
   END Crear_Cliente;

END Tareas.Cliente;
